const Router = require("koa-router");
const bodyParser = require("koa-bodyparser");
const path = require("path");
const fs = require("fs").promises;
const fsSync = require("fs");
const crypto = require("crypto");
const article = require("../utils/sql");
const { getCurrentTime } = require("../utils/times");
const multer = require("@koa/multer");
const send = require("koa-send");
const static = require("koa-static");

const fileUploadDownload = new Router();
fileUploadDownload.use(bodyParser());

// 配置常量
const UPLOAD_CONFIG = {
  MAX_FILE_SIZE: 100 * 1024 * 1024, // 100MB
  MAX_FILES: 10,
  ALLOWED_EXTENSIONS: [
    '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', // 图片
    '.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv', // 视频
    '.mp3', '.wav', '.flac', '.aac', '.ogg', // 音频
    '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', // 文档
    '.txt', '.md', '.csv', '.json', '.xml', // 文本
    '.zip', '.rar', '.7z', '.tar', '.gz' // 压缩包
  ],
  DANGEROUS_EXTENSIONS: ['.exe', '.bat', '.cmd', '.scr', '.pif', '.com', '.js', '.vbs', '.jar']
};

// 文件名安全化函数
function sanitizeFilename(filename) {
  // 移除危险字符
  const sanitized = filename.replace(/[<>:"/\\|?*\x00-\x1f]/g, '_');
  // 限制长度
  const maxLength = 255;
  if (sanitized.length > maxLength) {
    const ext = path.extname(sanitized);
    const name = path.basename(sanitized, ext);
    return name.substring(0, maxLength - ext.length) + ext;
  }
  return sanitized;
}

// 文件类型验证函数
function validateFileType(file) {
  const ext = path.extname(file.originalname).toLowerCase();

  // 检查是否为危险文件类型
  if (UPLOAD_CONFIG.DANGEROUS_EXTENSIONS.includes(ext)) {
    return { valid: false, error: '不允许上传可执行文件类型' };
  }

  // 检查是否为允许的文件类型
  if (!UPLOAD_CONFIG.ALLOWED_EXTENSIONS.includes(ext)) {
    return { valid: false, error: `不支持的文件类型: ${ext}` };
  }

  return { valid: true };
}

// 生成唯一文件名
function generateUniqueFilename(originalname) {
  const ext = path.extname(originalname);
  const name = path.basename(originalname, ext);
  const timestamp = Date.now();
  const random = crypto.randomBytes(4).toString('hex');
  return `${sanitizeFilename(name)}_${timestamp}_${random}${ext}`;
}

// 确保目录存在
async function ensureDirectoryExists(dirPath) {
  try {
    await fs.access(dirPath);
  } catch (error) {
    if (error.code === 'ENOENT') {
      await fs.mkdir(dirPath, { recursive: true });
    } else {
      throw error;
    }
  }
}

// 优化的存储配置
const storage = multer.diskStorage({
  destination: async function (req, file, cb) {
    try {
      const { pathname } = req._parsedUrl;
      const username = pathname.split("/")[3];

      if (!username || username.includes('..') || username.includes('/')) {
        return cb(new Error('无效的用户名'));
      }

      const uploadPath = path.join(__dirname, `../uploads/${username}`);
      await ensureDirectoryExists(uploadPath);
      cb(null, uploadPath);
    } catch (error) {
      cb(error);
    }
  },
  filename: function (req, file, cb) {
    try {
      // 验证文件类型
      const validation = validateFileType(file);
      if (!validation.valid) {
        return cb(new Error(validation.error));
      }

      const uniqueFilename = generateUniqueFilename(file.originalname);
      cb(null, uniqueFilename);
    } catch (error) {
      cb(error);
    }
  },
});

// 文件过滤器
const fileFilter = (req, file, cb) => {
  const validation = validateFileType(file);
  if (!validation.valid) {
    cb(new Error(validation.error), false);
  } else {
    cb(null, true);
  }
};

// 优化的multer配置
const uploadFile = multer({
  storage: storage,
  limits: {
    fileSize: UPLOAD_CONFIG.MAX_FILE_SIZE,
    files: UPLOAD_CONFIG.MAX_FILES,
    fields: 10,
    fieldSize: 1024 * 1024 // 1MB for form fields
  },
  fileFilter: fileFilter
});

// 检查文件是否已存在
async function checkFileExists(username, filename, size) {
  try {
    const userFiles = await article.getFile(username);
    if (userFiles.success && userFiles.data) {
      const existingFile = userFiles.data.find(file =>
        file.filename === filename && Math.abs(file.size - size) < 0.001
      );
      return existingFile || null;
    }
    return null;
  } catch (error) {
    console.error('检查文件存在性时出错:', error);
    return null;
  }
}

// 计算文件哈希值（用于重复文件检测）
async function calculateFileHash(filePath) {
  try {
    const fileBuffer = await fs.readFile(filePath);
    return crypto.createHash('md5').update(fileBuffer).digest('hex');
  } catch (error) {
    console.error('计算文件哈希值时出错:', error);
    return null;
  }
}

// 优化的文件上传路由
fileUploadDownload.post(
  "/upload/:username",
  async (ctx, next) => {
    try {
      // 预验证用户名
      const username = ctx.params.username;
      if (!username || username.includes('..') || username.includes('/')) {
        ctx.status = 400;
        ctx.body = {
          code: 400,
          msg: "无效的用户名"
        };
        return;
      }

      // 验证用户权限（可选：检查JWT token中的用户名是否匹配）
      // const tokenUsername = ctx.state.user?.username;
      // if (tokenUsername && tokenUsername !== username) {
      //   ctx.status = 403;
      //   ctx.body = { code: 403, msg: "无权限上传到此用户目录" };
      //   return;
      // }

      await next();
    } catch (error) {
      ctx.status = 500;
      ctx.body = {
        code: 500,
        msg: "服务器内部错误",
        error: error.message
      };
    }
  },
  uploadFile.single("file"),
  async (ctx) => {
    try {
      // 验证必要的请求数据
      const { userId, name, type, size, folderId, username } = ctx.request.body;

      if (!userId || !name || !type || !size) {
        ctx.status = 400;
        ctx.body = {
          code: 400,
          msg: "缺少必要的文件信息"
        };
        return;
      }

      // 验证文件是否成功上传
      if (!ctx.request.file) {
        ctx.status = 400;
        ctx.body = {
          code: 400,
          msg: "文件上传失败"
        };
        return;
      }

      const created_at = getCurrentTime();
      const user_id = parseInt(userId);
      const filename = sanitizeFilename(name);
      const folder_id = folderId || 0;
      const size_mb = parseFloat(size) / (1024 * 1024);
      const uploadedFile = ctx.request.file;

      // 构建文件路径
      const filePath = path.join(
        __dirname,
        `../uploads/${username}`,
        uploadedFile.filename
      );

      const relativeFilePath = path.relative(
        path.join(__dirname, `../uploads/${username}`),
        filePath
      );

      // 检查重复文件（可选功能）
      const existingFile = await checkFileExists(user_id, filename, size_mb);
      if (existingFile) {
        // 删除刚上传的文件，因为已存在
        try {
          await fs.unlink(filePath);
        } catch (unlinkError) {
          console.error('删除重复文件时出错:', unlinkError);
        }

        ctx.body = {
          code: 409,
          msg: "文件已存在",
          data: existingFile
        };
        return;
      }

      // 验证文件完整性
      const actualSize = uploadedFile.size;
      const expectedSize = parseInt(size);
      if (Math.abs(actualSize - expectedSize) > 1024) { // 允许1KB的差异
        ctx.status = 400;
        ctx.body = {
          code: 400,
          msg: "文件大小不匹配，可能上传不完整"
        };
        return;
      }

      // 保存文件信息到数据库
      console.log('准备保存到数据库:', {
        user_id,
        filename,
        size_mb,
        folder_id,
        type,
        created_at,
        relativeFilePath
      });

      const data = await article.addFile(
        user_id,
        filename,
        size_mb,
        folder_id,
        type,
        created_at,
        relativeFilePath
      );

      console.log('数据库操作结果:', data);

      if (!data.success) {
        // 如果数据库保存失败，删除已上传的文件
        try {
          console.log('数据库保存失败，尝试删除文件:', filePath);
          await fs.unlink(filePath);
          console.log('文件删除成功');
        } catch (unlinkError) {
          console.error('删除文件时出错:', unlinkError);
        }

        console.error('数据库保存失败:', data.msg);
        ctx.status = 500;
        ctx.body = {
          code: 500,
          msg: "数据库保存失败",
          error: data.msg
        };
        return;
      }

      // 成功响应
      ctx.body = {
        code: 200,
        msg: "文件上传成功",
        data: {
          ...data.data,
          originalName: name,
          storedName: uploadedFile.filename,
          size: size_mb,
          type: type
        }
      };

    } catch (error) {
      console.error('文件上传处理错误:', error);

      // 如果有上传的文件，尝试清理
      if (ctx.request.file && ctx.params.username) {
        try {
          const filePath = path.join(
            __dirname,
            `../uploads/${ctx.params.username}`,
            ctx.request.file.filename
          );
          console.log('尝试清理文件:', filePath);
          await fs.unlink(filePath);
          console.log('文件清理成功');
        } catch (unlinkError) {
          console.error('清理文件时出错:', unlinkError);
        }
      }

      ctx.status = 500;
      ctx.body = {
        code: 500,
        msg: "文件上传失败",
        error: error.message
      };
    }
  }
);

// Multer错误处理中间件
fileUploadDownload.use(async (ctx, next) => {
  try {
    await next();
  } catch (error) {
    console.error('文件操作错误:', error);

    // 处理Multer特定错误
    if (error.code) {
      switch (error.code) {
        case 'LIMIT_FILE_SIZE':
          ctx.status = 413;
          ctx.body = {
            code: 413,
            msg: `文件太大，最大允许 ${UPLOAD_CONFIG.MAX_FILE_SIZE / (1024 * 1024)}MB`
          };
          break;
        case 'LIMIT_FILE_COUNT':
          ctx.status = 413;
          ctx.body = {
            code: 413,
            msg: `文件数量超限，最多允许 ${UPLOAD_CONFIG.MAX_FILES} 个文件`
          };
          break;
        case 'LIMIT_UNEXPECTED_FILE':
          ctx.status = 400;
          ctx.body = {
            code: 400,
            msg: '意外的文件字段'
          };
          break;
        default:
          ctx.status = 400;
          ctx.body = {
            code: 400,
            msg: error.message || '文件上传错误'
          };
      }
    } else {
      ctx.status = 500;
      ctx.body = {
        code: 500,
        msg: error.message || '服务器内部错误'
      };
    }
  }
});

// 静态文件服务
fileUploadDownload.use(static(path.join(__dirname, "../uploads"), {
  maxAge: 24 * 60 * 60 * 1000, // 1天缓存
  gzip: true
}));

// 简化的文件下载路由 - GET方式
fileUploadDownload.get("/download/:username/:fileId", async (ctx) => {
  try {
    const { username, fileId } = ctx.params;

    // 验证参数
    if (!fileId || !username) {
      ctx.status = 400;
      ctx.body = "缺少必要参数";
      return;
    }

    if (username.includes('..') || username.includes('/')) {
      ctx.status = 400;
      ctx.body = "无效的用户名";
      return;
    }

    // 获取文件信息
    const res = await article.downloadFile(fileId);

    if (res.code !== 200 || !res.data || res.data.length === 0) {
      ctx.status = 404;
      ctx.body = "文件未找到";
      return;
    }

    const file = res.data[0];
    const filePath = path.join(__dirname, `../uploads/${username}`, file.relativeFilePath);

    // 检查文件是否存在
    try {
      await fs.access(filePath);
    } catch (error) {
      ctx.status = 404;
      ctx.body = "文件不存在于服务器";
      return;
    }

    // 获取文件统计信息
    const stats = await fs.stat(filePath);

    // 设置响应头
    ctx.set({
      'Content-Type': file.type || 'application/octet-stream',
      'Content-Length': stats.size,
      'Content-Disposition': `attachment; filename*=UTF-8''${encodeURIComponent(file.filename)}`,
      'Cache-Control': 'no-cache'
    });

    // 发送文件
    await send(ctx, file.relativeFilePath, {
      root: path.join(__dirname, `../uploads/${username}`)
    });

  } catch (error) {
    console.error('文件下载错误:', error);
    ctx.status = 500;
    ctx.body = "文件下载失败";
  }
});

// 保留原来的POST下载路由作为备用
fileUploadDownload.post("/download/:username", async (ctx) => {
  try {
    const { id } = ctx.request.body;
    const username = ctx.params.username;

    // 验证参数
    if (!id) {
      ctx.status = 400;
      ctx.body = {
        code: 400,
        msg: "缺少文件ID"
      };
      return;
    }

    if (!username || username.includes('..') || username.includes('/')) {
      ctx.status = 400;
      ctx.body = {
        code: 400,
        msg: "无效的用户名"
      };
      return;
    }

    // 获取文件信息
    const res = await article.downloadFile(id);

    if (res.code !== 200 || !res.data || res.data.length === 0) {
      console.log('❌ 数据库中未找到文件');
      ctx.status = 404;
      ctx.body = {
        code: 404,
        msg: "文件未找到"
      };
      return;
    }

    console.log('✅ 数据库查询成功，找到文件');

    const file = res.data[0];
    const filePath = path.join(__dirname, `../uploads/${username}`, file.relativeFilePath);

    // 检查文件是否存在
    try {
      await fs.access(filePath);
    } catch (error) {
      ctx.status = 404;
      ctx.body = {
        code: 404,
        msg: "文件不存在于服务器"
      };
      return;
    }

    // 获取文件统计信息
    const stats = await fs.stat(filePath);

    // 设置响应头
    ctx.set({
      'Content-Type': file.type || 'application/octet-stream',
      'Content-Length': stats.size,
      'Content-Disposition': `attachment; filename*=UTF-8''${encodeURIComponent(file.filename)}`,
      'Cache-Control': 'no-cache'
    });

    // 发送文件
    await send(ctx, file.relativeFilePath, {
      root: path.join(__dirname, `../uploads/${username}`)
    });

  } catch (error) {
    console.error('文件下载错误:', error);
    ctx.status = 500;
    ctx.body = {
      code: 500,
      msg: "文件下载失败",
      error: error.message
    };
  }
});

// 批量文件上传路由
fileUploadDownload.post(
  "/upload-multiple/:username",
  uploadFile.array("files", UPLOAD_CONFIG.MAX_FILES),
  async (ctx) => {
    try {
      const { userId, folderId, username } = ctx.request.body;

      if (!userId) {
        ctx.status = 400;
        ctx.body = {
          code: 400,
          msg: "缺少用户ID"
        };
        return;
      }

      if (!ctx.request.files || ctx.request.files.length === 0) {
        ctx.status = 400;
        ctx.body = {
          code: 400,
          msg: "没有文件被上传"
        };
        return;
      }

      const created_at = getCurrentTime();
      const user_id = parseInt(userId);
      const folder_id = folderId || 0;
      const results = [];
      const errors = [];

      // 处理每个文件
      for (const file of ctx.request.files) {
        try {
          const size_mb = file.size / (1024 * 1024);
          const relativeFilePath = path.relative(
            path.join(__dirname, `../uploads/${username}`),
            file.path
          );

          const data = await article.addFile(
            user_id,
            sanitizeFilename(file.originalname),
            size_mb,
            folder_id,
            file.mimetype,
            created_at,
            relativeFilePath
          );

          if (data.success) {
            results.push({
              filename: file.originalname,
              size: size_mb,
              type: file.mimetype,
              data: data.data
            });
          } else {
            errors.push({
              filename: file.originalname,
              error: data.msg
            });
          }
        } catch (error) {
          errors.push({
            filename: file.originalname,
            error: error.message
          });
        }
      }

      ctx.body = {
        code: 200,
        msg: `成功上传 ${results.length} 个文件${errors.length > 0 ? `，${errors.length} 个文件失败` : ''}`,
        data: {
          success: results,
          errors: errors,
          total: ctx.request.files.length,
          successCount: results.length,
          errorCount: errors.length
        }
      };

    } catch (error) {
      console.error('批量文件上传错误:', error);
      ctx.status = 500;
      ctx.body = {
        code: 500,
        msg: "批量文件上传失败",
        error: error.message
      };
    }
  }
);

// 获取上传配置信息
fileUploadDownload.get("/upload-config", async (ctx) => {
  ctx.body = {
    code: 200,
    msg: "获取配置成功",
    data: {
      maxFileSize: UPLOAD_CONFIG.MAX_FILE_SIZE,
      maxFiles: UPLOAD_CONFIG.MAX_FILES,
      allowedExtensions: UPLOAD_CONFIG.ALLOWED_EXTENSIONS,
      maxFileSizeMB: UPLOAD_CONFIG.MAX_FILE_SIZE / (1024 * 1024)
    }
  };
});

// 文件预览路由（用于图片、视频等）
fileUploadDownload.get("/preview/:username/:filename", async (ctx) => {
  try {
    const { username, filename } = ctx.params;

    if (!username || !filename || username.includes('..') || filename.includes('..')) {
      ctx.status = 400;
      ctx.body = {
        code: 400,
        msg: "无效的参数"
      };
      return;
    }

    const filePath = path.join(__dirname, `../uploads/${username}`, filename);

    try {
      await fs.access(filePath);
      const stats = await fs.stat(filePath);

      // 设置缓存头
      ctx.set({
        'Cache-Control': 'public, max-age=86400', // 1天缓存
        'Last-Modified': stats.mtime.toUTCString()
      });

      await send(ctx, filename, {
        root: path.join(__dirname, `../uploads/${username}`)
      });
    } catch (error) {
      ctx.status = 404;
      ctx.body = {
        code: 404,
        msg: "文件不存在"
      };
    }
  } catch (error) {
    console.error('文件预览错误:', error);
    ctx.status = 500;
    ctx.body = {
      code: 500,
      msg: "文件预览失败"
    };
  }
});

// 图片访问路由 - 使用简单的文件名参数
fileUploadDownload.get("/image/:username/:filename", async (ctx) => {
  try {
    const { username, filename } = ctx.params;

    if (!username || !filename || username.includes('..') || filename.includes('..')) {
      ctx.status = 400;
      ctx.body = {
        code: 400,
        msg: "无效的参数"
      };
      return;
    }

    // 清理路径，将反斜杠转换为正斜杠
    const cleanFilename = filename.replace(/\\/g, '/');
    const filePath = path.join(__dirname, `../uploads/${username}`, cleanFilename);

    try {
      await fs.access(filePath);
      const stats = await fs.stat(filePath);

      const fileSize = stats.size;
      const range = ctx.headers.range;

      // 获取文件扩展名来设置正确的Content-Type
      const ext = path.extname(filePath).toLowerCase();
      const mimeTypes = {
        '.jpg': 'image/jpeg',
        '.jpeg': 'image/jpeg',
        '.png': 'image/png',
        '.gif': 'image/gif',
        '.bmp': 'image/bmp',
        '.webp': 'image/webp',
        '.svg': 'image/svg+xml',
        // 添加视频和音频类型
        '.mp4': 'video/mp4',
        '.webm': 'video/webm',
        '.ogg': 'video/ogg',
        '.avi': 'video/x-msvideo',
        '.mov': 'video/quicktime',
        '.wmv': 'video/x-ms-wmv',
        '.flv': 'video/x-flv',
        '.mkv': 'video/x-matroska',
        '.mp3': 'audio/mpeg',
        '.wav': 'audio/wav',
        '.flac': 'audio/flac',
        '.aac': 'audio/aac',
        '.m4a': 'audio/mp4'
      };

      const contentType = mimeTypes[ext] || 'application/octet-stream';

      // 检查是否是视频或音频文件
      const isVideo = contentType.startsWith('video/');
      const isAudio = contentType.startsWith('audio/');
      const supportsRange = isVideo || isAudio;

      // 设置基本响应头
      const headers = {
        'Content-Type': contentType,
        'Cache-Control': supportsRange ? 'public, max-age=3600' : 'public, max-age=86400',
        'Last-Modified': stats.mtime.toUTCString()
      };

      if (supportsRange) {
        headers['Accept-Ranges'] = 'bytes';
      }

      ctx.set(headers);

      // 如果是视频/音频文件且有Range请求，处理Range请求
      if (supportsRange && range) {
        // 解析Range请求
        const parts = range.replace(/bytes=/, "").split("-");
        const start = parseInt(parts[0], 10);
        const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;

        // 验证Range
        if (start >= fileSize || end >= fileSize || start > end) {
          ctx.status = 416; // Range Not Satisfiable
          ctx.set('Content-Range', `bytes */${fileSize}`);
          return;
        }

        const chunkSize = (end - start) + 1;

        // 设置206 Partial Content响应头
        ctx.status = 206;
        ctx.set({
          'Content-Range': `bytes ${start}-${end}/${fileSize}`,
          'Content-Length': chunkSize.toString()
        });

        // 创建文件流
        const stream = fsSync.createReadStream(filePath, { start, end });
        ctx.body = stream;
      } else if (supportsRange) {
        // 视频/音频文件但没有Range请求，返回整个文件
        ctx.status = 200;
        ctx.set('Content-Length', fileSize.toString());
        ctx.body = fsSync.createReadStream(filePath);
      } else {
        // 图片文件，使用koa-send
        await send(ctx, cleanFilename, {
          root: path.join(__dirname, `../uploads/${username}`)
        });
      }
    } catch (error) {
      ctx.status = 404;
      ctx.body = {
        code: 404,
        msg: "图片不存在"
      };
    }
  } catch (error) {
    console.error('图片访问错误:', error);
    ctx.status = 500;
    ctx.body = {
      code: 500,
      msg: "图片访问失败"
    };
  }
});

module.exports = fileUploadDownload;
